#pragma once
#include<iostream>
using namespace std;



namespace bit
{
//c++98
//管理权被转移之后，可能会导致被拷贝对象调用野指针
template<class T>
class auto_ptr
{
public:
    auto_ptr(T* ptr):_ptr(ptr)
    {
      
  }
    //管理权转移
    auto_ptr(auto_ptr<T>& ap)
    :_ptr(ap._ptr)
    {
        ap._ptr=nullptr;
    }
    ~auto_ptr()
    {
        cout<<"delete ptr"<<endl;
        delete _ptr;
    }
    
    //实现和指针一样
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
private:
    T* _ptr;
};

//c++11
//unique_ptr是如何解决，管理权被转移之后，可能会导致被拷贝对象调用野指针呢？
//就是禁止拷贝
//
template<class T>
class unique_ptr
{
public:
    unique_ptr(T* ptr):_ptr(ptr)
    {
      
  }
    
    ~unique_ptr()
    {
        cout<<"delete ptr"<<endl;
        delete _ptr;
    }
    
    //实现和指针一样
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
    //c++11的做法
    unique_ptr(const unique_ptr<T>& up)=delete;
    unique_ptr<T>& operator=(const unique_ptr<T>& up)=delete;//赋值
    
//private:
//    //c++98的实现
//    //1.只声明不实现
//    //2.限定私有
//    unique_ptr(const unique_ptr<T>& up);
//    unique_ptr<T>& operator=(const unique_ptr<T>& up);//赋值
private:
    T* _ptr;
};

//shared_ptr是通过引用计数方式来实现，拷贝和赋值
//在堆上申请一个空间作为引用计数
template<class T>
class shared_ptr
{
public:
    shared_ptr(T* ptr=nullptr)
    :_ptr(ptr),_pcount(new int(1))
    {
      
    }
    
    ~shared_ptr()
    {
        if(--(*_pcount)==0)
        {
            cout<<"delete _ptr: "<<_ptr<<endl;
            delete _ptr;
            delete _pcount;
        }
    }
    
    //实现和指针一样
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
    
    //在堆上开辟一段空间
    shared_ptr(const shared_ptr<T>& sp)
    :_ptr(sp._ptr)
    ,_pcount(sp._pcount)
    {
        (*_pcount)++;
    }
    
    shared_ptr<T>& operator=(const shared_ptr<T>& sp)
    //赋值可能有很多情况
    //1）sp1赋值给sp2
    //2）自己给自己赋值
    //      1> sp1=sp1//sp1赋值给sp1
    //      2> sp1=sp2//sp1赋值给sp2
    //         sp1=sp2//sp1赋值给sp2
    {
        if(_ptr!=sp._ptr)//判断是否赋值给自己
        {
            if(--(*_pcount)==0)
            {
                delete _ptr;
                delete _pcount;
            }
            _ptr=sp._ptr;
            _pcount=sp._pcount;
            
            ++(*_pcount);
        }
        return *this;
    }
    int use_count() const
    {
        return *_pcount;
    }

    T* get() const
    {
        return _ptr;
    }
private:
    T* _ptr;
    int* _pcount;
};

//用于解决循环引用
template<class T>
    class weak_ptr
    {
    public:
        weak_ptr()
            :_ptr(nullptr)
        {}

        weak_ptr(const shared_ptr<T>& sp)
            :_ptr(sp.get())
        {}

        weak_ptr<T>& operator=(const shared_ptr<T>& sp)
        {
            _ptr = sp.get();
            return *this;
        }

        // 像指针一样
        T& operator*()
        {
            return *_ptr;
        }

        T* operator->()
        {
            return _ptr;
        }
    private:
        T* _ptr;
    };
}
